package com.own.demo.blockchain.blockchain2;

import com.google.gson.GsonBuilder;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static org.junit.Assert.assertTrue;

/**
 * @Author liwenfeng
 * @Description dongruan
 * @Date 2023/07/15/10:55
 * @Version 1.0
 */
public class NoobChain {
    // 定义一个前缀4，这实际上意味这我们希望哈希以4个零开始
    public static int prefix = 4;
    // 区块链
    public static List<Block1> blockchain = new ArrayList<>();
    public static String prefixString = new String(new char[prefix]).replace('\0', '0');
    public static void main(String[] args) {
        // 每new一个Block块就会生成一个特殊的string标识
        // Block1 genesisBlock = new Block1("0", "78,95,123", new Date().getTime());
        // System.out.println("Hash for Block1: " + genesisBlock.getHash());
        // Block1 secondBlock = new Block1(genesisBlock.getHash(), "87,158,231561", new Date().getTime());
        // System.out.println("Hash for Block2 = " + secondBlock.getHash());
        // Block1 thirdBlock = new Block1(secondBlock.getHash(), "545,897256,2568558", new Date().getTime());
        // System.out.println("Hash for Block3 = " + thirdBlock.getHash());

        blockchain.add(new Block1("0", "这是第1个区块", new Date().getTime()));
        System.out.println("Trying to Mine block 1... ");
        System.out.println("nonce = " + blockchain.get(0).minBlock(prefix));
        givenBlokchain_whenNewBlockAdded_thenSuccess();
        givenBlokchain_whenNewBlockAdded_thenSuccess();
        String blockchainJson = new GsonBuilder().setPrettyPrinting().create().toJson(blockchain);
        System.out.println("blockchainJson : "+ "\n" + blockchainJson);

        Boolean aBoolean = givenenBlockchain_whenValidated_thenSuccess();
        if(!aBoolean){
            System.out.println("警告：区块链不完整！！！");
        }else{
            System.out.println("挖矿成功！");
        }
    }

    // 在区块链里添加一个块
    public static void givenBlokchain_whenNewBlockAdded_thenSuccess() {
        // 建立一个区块
        Block1 newBlock = new Block1(blockchain.get(blockchain.size() - 1).getHash(), "这是第" + (blockchain.size() + 1) + "个区块", new Date().getTime());
        // 找到四个0的区块
        newBlock.minBlock(prefix);
        // 再次验证是否正确
        assertTrue(newBlock.getHash().substring(0, prefix).equals(prefixString));
        // 添加一个区块
        blockchain.add(newBlock);
    }

    // 区块链验证
    public static Boolean givenenBlockchain_whenValidated_thenSuccess() {
        boolean flag = true;
        for (int i = 0; i < blockchain.size(); i++) {
            // 得到前区块的hash值
            String previousHash = i == 0 ? "0" : blockchain.get(i - 1).getHash();
            //进行真伪判断
            //原理：判断hash是否等于计算的hash//判断储存的前区块hash是否等于真正的hash//判断是否满足“挖矿”成功的条件
            System.out.println("判断hash是否等于计算的hash:" + "\n" + blockchain.get(i).getHash() + "\n" + blockchain.get(i).calculateBlockHash());
            System.out.println("判断储存的前区块hash是否等于真正的hash" + "\n" + previousHash + "\n" + blockchain.get(i).getPreviousHash());
            System.out.println("判断是否满足“挖矿”成功的条件" + "\n" + blockchain.get(i).getHash().substring(0, prefix) + "\n" + prefixString);
            flag = blockchain.get(i).getHash().equals(blockchain.get(i).calculateBlockHash())
                    && previousHash.equals(blockchain.get(i).getPreviousHash()) && blockchain.get(i).getHash().substring(0, prefix).equals(prefixString);
            //一次不行就直接跳出
            if (!flag) {
                break;
            }
        }
        //进行正确性检验
        // assertTrue(flag);
        return flag;
    }
}
